{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'reload' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-1-add24ded000a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0msys\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mreload\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msys\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msetdefaultencoding\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"utf-8\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mNameError\u001b[0m: name 'reload' is not defined"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "reload(sys)\n",
    "sys.setdefaultencoding(\"utf-8\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#导入必要的工具包\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "from collections import  defaultdict\n",
    "import  scipy.sparse as ss\n",
    "\n",
    "\n",
    "import pickle\n",
    "import scipy.io as sio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "#读取数据\n",
    "train=pd.read_csv('triplet_dataset_sub.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(22511, 3)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "\n",
    "#将数据分割训练数据与测试数据\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "# 随机采样20%的数据构建测试样本，其余作为训练样本\n",
    "train, test = train_test_split(train, random_state=33, test_size=0.4)\n",
    "train.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "#每个用户的总播放次数\n",
    "triplet_train_sum_df = train[['user','play_count']].groupby('user').sum().reset_index()\n",
    "triplet_train_sum_df.rename(columns={'play_count':'total_play_count'},inplace=True)\n",
    "\n",
    "#每首歌曲的播放比例\n",
    "train = pd.merge(train,triplet_train_sum_df)\n",
    "train['fractional_play_count'] = train['play_count']/train['total_play_count']\n",
    "del triplet_train_sum_df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user</th>\n",
       "      <th>song</th>\n",
       "      <th>play_count</th>\n",
       "      <th>total_play_count</th>\n",
       "      <th>fractional_play_count</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>30cc99a1b03a19cc162b286c76047e58371ffb3d</td>\n",
       "      <td>SOOXJDU12A8AE47ECB</td>\n",
       "      <td>1</td>\n",
       "      <td>43</td>\n",
       "      <td>0.023256</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>30cc99a1b03a19cc162b286c76047e58371ffb3d</td>\n",
       "      <td>SOTORXA12A58A79338</td>\n",
       "      <td>1</td>\n",
       "      <td>43</td>\n",
       "      <td>0.023256</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>30cc99a1b03a19cc162b286c76047e58371ffb3d</td>\n",
       "      <td>SODJWHY12A8C142CCE</td>\n",
       "      <td>1</td>\n",
       "      <td>43</td>\n",
       "      <td>0.023256</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>30cc99a1b03a19cc162b286c76047e58371ffb3d</td>\n",
       "      <td>SOWSSRH12A58A7CE5D</td>\n",
       "      <td>1</td>\n",
       "      <td>43</td>\n",
       "      <td>0.023256</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>30cc99a1b03a19cc162b286c76047e58371ffb3d</td>\n",
       "      <td>SOXPDDQ12A58A76829</td>\n",
       "      <td>1</td>\n",
       "      <td>43</td>\n",
       "      <td>0.023256</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                       user                song  play_count  \\\n",
       "0  30cc99a1b03a19cc162b286c76047e58371ffb3d  SOOXJDU12A8AE47ECB           1   \n",
       "1  30cc99a1b03a19cc162b286c76047e58371ffb3d  SOTORXA12A58A79338           1   \n",
       "2  30cc99a1b03a19cc162b286c76047e58371ffb3d  SODJWHY12A8C142CCE           1   \n",
       "3  30cc99a1b03a19cc162b286c76047e58371ffb3d  SOWSSRH12A58A7CE5D           1   \n",
       "4  30cc99a1b03a19cc162b286c76047e58371ffb3d  SOXPDDQ12A58A76829           1   \n",
       "\n",
       "   total_play_count  fractional_play_count  \n",
       "0                43               0.023256  \n",
       "1                43               0.023256  \n",
       "2                43               0.023256  \n",
       "3                43               0.023256  \n",
       "4                43               0.023256  "
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "items = list(train['song'])\n",
    "users = list(train['user'].unique())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number of Users : 784\n",
      "number of Songs : 22511\n"
     ]
    }
   ],
   "source": [
    "#倒排表的生成、用户和item重新建立索引\n",
    "n_users = len(users)\n",
    "n_items = len(items)\n",
    "\n",
    "print(\"number of Users : %d\" % n_users)\n",
    "print(\"number of Songs : %d\" % n_items)\n",
    "\n",
    "\n",
    "user_items = defaultdict(set)\n",
    "item_users = defaultdict(set)\n",
    "\n",
    "user_items_scores = ss.dok_matrix((n_users,n_items))\n",
    "\n",
    "user_index = dict()\n",
    "item_index = dict()\n",
    "\n",
    "for i,u in enumerate(users):\n",
    "    user_index[u] = i\n",
    "\n",
    "for i,e in enumerate(items):\n",
    "    item_index[e] = i\n",
    "\n",
    "n_records = train.shape[0]\n",
    "for i in range(n_records):\n",
    "    user_index_i = user_index[train.iloc[i]['user'] ]\n",
    "    item_index_i = item_index[train.iloc[i]['song'] ]\n",
    "    \n",
    "    user_items[user_index_i].add(item_index_i)\n",
    "    item_users[item_index_i].add(user_index_i)\n",
    "    score = train.iloc[i]['fractional_play_count']\n",
    "    user_items_scores[user_index_i,item_index_i] = score\n",
    "\n",
    "#倒排表\n",
    "pickle.dump(user_items,open(\"user_items.pkl\",'wb'))\n",
    "pickle.dump(item_users,open(\"item_users.pkl\",'wb'))\n",
    "\n",
    "#保存用户-物品关系矩阵R\n",
    "sio.mmwrite(\"user_items_scores\",user_items_scores)\n",
    "\n",
    "#重新建立索引表\n",
    "pickle.dump(user_index,open(\"user_index.pkl\",'wb'))\n",
    "pickle.dump(item_index,open(\"item_index.pkl\",'wb'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i=:0 \n"
     ]
    }
   ],
   "source": [
    "#事先计算好item的相似性矩阵（电脑内存限制，无法生成相似度矩阵）\n",
    "similarity_matrix = np.matrix(np.zeros(shape=(n_items,n_items)),float)\n",
    "\n",
    "for i in range(n_items):\n",
    "    users_i = item_users[i]\n",
    "    similarity_matrix[i,i] = 1.0\n",
    "    \n",
    "    if(i % 10 == 0):\n",
    "        print(\"i=:%d \"%(i))\n",
    "        \n",
    "        for j in range(i+1,n_items):\n",
    "            users_j = item_users[j]\n",
    "            \n",
    "            users_intersection = users_i.intersection(users_j)\n",
    "            \n",
    "            if len(users_intersection) != 0:\n",
    "                users_union = users_i.union(users_j)\n",
    "                similarity_matrix[j,i] = float(len(users_intersection))/float(len(users_union))\n",
    "            else:\n",
    "                similarity_matrix[j,i] = 0\n",
    "        similarity_matrix[i,j] = similarity_matrix[j,i]\n",
    "        pickle.dump(similarity_matrix,open(\"items_similarity.pkl\",'wb'))\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
